﻿using Abp.Domain.Entities;
using Abp.Domain.Repositories;
using Abp.EntityFramework;
using Abp.EntityFramework.Repositories;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Linq.Expressions;
using System.Data.SqlClient;
using System.Data.Entity;
using ACN.Mail.IRepositories;
using System.Data.Entity.Infrastructure;

namespace ACN.Mail.EntityFramework.Repositories
{

    public abstract class CustomRepositoryBase<TDbContext, TEntity, TPrimaryKey> : EfRepositoryBase<TDbContext, TEntity, TPrimaryKey>, IRepositoryBase<TEntity, TPrimaryKey>
        where TEntity : class, IEntity<TPrimaryKey>
        where TDbContext : DbContext
    {
        public CustomRepositoryBase(IDbContextProvider<TDbContext> dbContextProvider)
            : base(dbContextProvider)
        {

        }

        //add common methods for all repositories

        #region SQL

        private SqlParameter[] GetParameters(IDictionary<string, object> parameters)
        {
            SqlParameter[] args = new SqlParameter[parameters.Count];
            int i = 0;
            foreach (var item in parameters)
            {
                SqlParameter arg = new SqlParameter(item.Key, item.Value);
                args[i] = arg;
                i++;
            }
            return args;
        }

        public List<TEntity> FromSql(string sql, params object[] parameters)
        {
            //return this.Table.FromSql(sql, parameters).ToList(); //.Net Core请使用FromSql方法.
            DbRawSqlQuery<TEntity> query = this.Context.Database.SqlQuery<TEntity>(sql, parameters);
            List<TEntity> list = query.ToList();
            return list;
        }

        public List<TEntity> FromSql(string sql, IDictionary<string, object> parameters)
        {
            //SqlParameter[] args = this.GetParameters(parameters);
            //return this.Table.FromSql(sql, args).ToList();
            DbRawSqlQuery<TEntity> query;
            if (parameters != null && parameters.Count > 0)
            {
                SqlParameter[] args = new SqlParameter[parameters.Count];
                int i = 0;
                foreach (var item in parameters)
                {
                    SqlParameter arg = new SqlParameter(item.Key, item.Value);
                    args[i] = arg;
                    i++;
                }
                query = this.Context.Database.SqlQuery<TEntity>(sql, args);
            }
            else
            {
                query = this.Context.Database.SqlQuery<TEntity>(sql);
            }
            List<TEntity> list = query.ToList();
            return list;

        }

        public Task<List<TEntity>> FromSqlAsync(string sql, params object[] parameters)
        {
            DbRawSqlQuery<TEntity> query = this.Context.Database.SqlQuery<TEntity>(sql, parameters);
            return query.ToListAsync();
        }

        public Task<List<TEntity>> FromSqlAsync(string sql, IDictionary<string, object> parameters)
        {
            DbRawSqlQuery<TEntity> query;
            if (parameters != null && parameters.Count > 0)
            {
                SqlParameter[] args = new SqlParameter[parameters.Count];
                int i = 0;
                foreach (var item in parameters)
                {
                    SqlParameter arg = new SqlParameter(item.Key, item.Value);
                    args[i] = arg;
                    i++;
                }
                query = this.Context.Database.SqlQuery<TEntity>(sql, args);
            }
            else
            {
                query = this.Context.Database.SqlQuery<TEntity>(sql);
            }
            return query.ToListAsync();
        }

        public int Execute(string sql, params object[] parameters)
        {
            int result = this.Context.Database.ExecuteSqlCommand(sql, parameters);
            return result;
        }

        public int Execute(string sql, IDictionary<string, object> parameters)
        {
            return 0;
            //int result;
            //if (parameters != null && parameters.Count > 0)
            //{
            //    SqlParameter[] args = new SqlParameter[parameters.Count];
            //    int i = 0;
            //    foreach (var item in parameters)
            //    {
            //        SqlParameter arg = new SqlParameter(item.Key, item.Value);
            //        args[i] = arg;
            //        i++;
            //    }
            //    result = this.Context.Database.ExecuteSqlCommand(sql, args);
            //}
            //else
            //{
            //    result = this.Context.Database.ExecuteSqlCommand(sql);
            //}
            //return result;
        }

        #endregion SQL

        #region  Including异步重载

        public async Task<List<TEntity>> GetAllListAsync(params Expression<Func<TEntity, object>>[] includingPropertys)
        {
            return await GetAllIncluding(includingPropertys).ToListAsync();
        }

        public async Task<List<TEntity>> GetAllListAsync(Expression<Func<TEntity, bool>> predicate, params Expression<Func<TEntity, object>>[] includingPropertys)
        {
            return await GetAllIncluding(includingPropertys).Where(predicate).ToListAsync();
        }

        public async Task<TEntity> SingleAsync(Expression<Func<TEntity, bool>> predicate, params Expression<Func<TEntity, object>>[] includingPropertys)
        {
            return await GetAllIncluding(includingPropertys).SingleAsync(predicate);
        }

        public async Task<TEntity> FirstOrDefaultAsync(TPrimaryKey id, params Expression<Func<TEntity, object>>[] includingPropertys)
        {
            return await GetAllIncluding(includingPropertys).FirstOrDefaultAsync(CreateEqualityExpressionForId(id));
        }

        public async Task<TEntity> FirstOrDefaultAsync(Expression<Func<TEntity, bool>> predicate, params Expression<Func<TEntity, object>>[] includingPropertys)
        {
            return await GetAllIncluding(includingPropertys).FirstOrDefaultAsync(predicate);
        }


        #endregion
    }


    public abstract class CustomRepositoryBase<TDbContext, TEntity> : CustomRepositoryBase<TDbContext, TEntity, int>, IRepository<TEntity>
        where TEntity : class, IEntity<int>
        where TDbContext : DbContext
    {
        public CustomRepositoryBase(IDbContextProvider<TDbContext> dbContextProvider)
            : base(dbContextProvider)
        {
        }
    }
}
